package com.cloudfun.campusshare.service.impl;

import com.cloudfun.campusshare.common.constant.DeviceStatus;
import com.cloudfun.campusshare.common.constant.DeviceType;
import com.cloudfun.campusshare.device.protocol.constant.PumpConstant;
import com.cloudfun.campusshare.device.protocol.constant.PumpWorkStatus;
import com.cloudfun.campusshare.entity.DeviceEntity;
import com.cloudfun.campusshare.entity.DevicePropertyEntity;
import com.cloudfun.campusshare.repo.DeviceEntityRepo;
import com.cloudfun.campusshare.repo.DevicePropertyRepo;
import com.cloudfun.campusshare.service.DeviceOrderService;
import com.cloudfun.campusshare.service.DevicePropertyService;
import com.cloudfun.msgsubscribe.DeviceInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by Huqin on 2020/2/21
 */
@Slf4j
@Service
public class DevicePropertyServiceImpl implements DevicePropertyService {

    @Autowired
    private DevicePropertyRepo devicePropertyRepo;

    @Autowired
    private DeviceEntityRepo deviceEntityRepo;

    @Autowired
    private DeviceOrderService deviceOrderService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void setProperty(String deviceId, String propName, String propVal) {
        if (StringUtils.equals(propName, "remainingTimeMM")) {
            this.setProperty(deviceId, "realRemainingTimeMM", propVal);
        }
        DevicePropertyEntity devicePropertyEntity = devicePropertyRepo.findByDeviceIdAndPropertyName(deviceId, propName);
        if (null == devicePropertyEntity) {
            devicePropertyEntity = DevicePropertyEntity.builder()
                    .deviceId(deviceId)
                    .propertyName(propName)
                    .build();
        }
        if (StringUtils.equals(devicePropertyEntity.getPropertyValue(), propVal)) {
            return;
        }
        devicePropertyEntity.setPropertyValue(propVal);
        devicePropertyRepo.save(devicePropertyEntity);
    }

    @Override
    public String getProperty(String deviceId, String propName) {
        DevicePropertyEntity devicePropertyEntity = devicePropertyRepo.findByDeviceIdAndPropertyName(deviceId, propName);
        if (null == devicePropertyEntity) {
            return null;
        }
        return devicePropertyEntity.getPropertyValue();
    }

    @Override
    public String getRealRemainTime(String deviceId) {
        DevicePropertyEntity devicePropertyEntity = devicePropertyRepo.findByDeviceIdAndPropertyName(deviceId, "realRemainingTimeMM");
        if (null != devicePropertyEntity) {
            return devicePropertyEntity.getPropertyValue();
        }
        return null;
    }

    @Override
    @Transactional
    public void updateProperty(DeviceInfo deviceInfo) {
        DeviceEntity deviceEntity = deviceEntityRepo.findByImei(deviceInfo.getImei());
        if (Objects.isNull(deviceEntity)) {
            return;
        }
        DevicePropertyEntity timestampEntity = devicePropertyRepo.findByDeviceIdAndPropertyName(deviceEntity.getId(), "timestamp");
        if (null != timestampEntity) {
            String lastUpdateTime = timestampEntity.getPropertyValue();
            if (Long.parseLong(deviceInfo.getTimestamp()) < Long.parseLong(lastUpdateTime)) {
                log.error("设备：{}的属性变更请求时间戳：{}小于属性最近更新时间戳：{}，不进行更新", deviceEntity.getId(), deviceInfo.getTimestamp(), lastUpdateTime);
                return;
            }
        }
        this.setProperty(deviceEntity.getId(), "timestamp", deviceInfo.getTimestamp());

        for (Map.Entry<String, String> entry : deviceInfo.getAttrs().entrySet()) {
            String propName = entry.getKey();
            if (StringUtils.isBlank(propName)) {
                return;
            }
            this.setProperty(deviceEntity.getId(), propName, entry.getValue());
        }
        if (StringUtils.equals(deviceInfo.getAttrs().get("cyclePhaseCD"), "0")
                || StringUtils.equals(deviceInfo.getAttrs().get("cyclePhaseCW"), "0")) {
            // 设备停止
            this.onStopped(deviceEntity);
        }
        if ((deviceInfo.getAttrs().containsKey("cyclePhaseCD") && !deviceInfo.getAttrs().get("cyclePhaseCD").equals("0"))
                || (deviceInfo.getAttrs().containsKey("cyclePhaseCW") && !deviceInfo.getAttrs().get("cyclePhaseCW").equals("0"))) {
            // 设备启动
            this.onStarted(deviceEntity);
        }
        // 暂停
        if (deviceEntity.getStatus() == DeviceStatus.RUNNING && StringUtils.equals(deviceInfo.getAttrs().get("started"), "false")) {
            this.onPaused(deviceEntity);
        }
        if (deviceEntity.getStatus() == DeviceStatus.NOT_RUNNING) {
            // 设置真实剩余时间
            this.setProperty(deviceEntity.getId(), "realRemainingTimeMM", "0");
        }
    }

    /**
     * 暂停
     *
     * @param deviceEntity
     */
    private void onPaused(DeviceEntity deviceEntity) {
        if (!DeviceStatus.PAUSE.equals(deviceEntity.getStatus())) {
            // 更新运行状态
            deviceEntity.setStatus(DeviceStatus.PAUSE);
            deviceEntityRepo.saveAndFlush(deviceEntity);
        }
    }

    /**
     * 设备启动后的动作
     *
     * @param deviceEntity
     */
    private void onStarted(DeviceEntity deviceEntity) {
        if (!DeviceStatus.RUNNING.equals(deviceEntity.getStatus())) {
            // 更新运行状态
            deviceEntity.setStatus(DeviceStatus.RUNNING);
            deviceEntityRepo.saveAndFlush(deviceEntity);
        }
    }

    /**
     * 设备停止后的动作
     *
     * @param deviceEntity
     */
    private void onStopped(DeviceEntity deviceEntity) {
        String deviceId = deviceEntity.getId();
        if (!DeviceStatus.NOT_RUNNING.equals(deviceEntity.getStatus())) {
            // 更新运行状态
            deviceEntity.setStatus(DeviceStatus.NOT_RUNNING);
            deviceEntityRepo.saveAndFlush(deviceEntity);
            deviceOrderService.onDeviceStop(deviceId);
        }
    }

    @Override
    public Map<String, String> getDevicePropertiesByDeviceId(String deviceId) {
        List<DevicePropertyEntity> devicePropertyEntities = devicePropertyRepo.findAllByDeviceId(deviceId);
        if (CollectionUtils.isEmpty(devicePropertyEntities)) {
            return new HashMap<>();
        }
        return devicePropertyEntities.stream().collect(Collectors.toMap(DevicePropertyEntity::getPropertyName, DevicePropertyEntity::getPropertyValue));
    }

    @Override
    public Map<String, String> getDevicePropertiesByImei(String imei) {
        DeviceEntity deviceEntity = deviceEntityRepo.findByImei(imei);
        if (null == deviceEntity) {
            return new HashMap<>();
        }
        return this.getDevicePropertiesByDeviceId(deviceEntity.getId());
    }

    @Override
    @Transactional
    public void updatePumpProperty(Map<String, String> allProperties,DeviceInfo deviceInfo) {
        DeviceEntity deviceEntity = updateProperties(deviceInfo);
        if(deviceEntity == null){
            return;
        }
        // 如果绑定的设备类型既不是单泵也不是双泵，说明绑定错误，需要修改
        if(!DeviceType.PUMP_LA_1.getName().equals(deviceEntity.getDeviceType()) && !DeviceType.PUMP_LA_2.getName().equals(deviceEntity.getDeviceType())){
            log.error("{}所属设备绑定错误，原绑定{}",deviceEntity.getImei(),deviceEntity.getDeviceType());
            // 默认绑定双泵
            deviceEntity.setDeviceType(DeviceType.PUMP_LA_2.getName());
            deviceEntity.setProductType(DeviceType.PUMP_LA_2.getProductType());
            deviceEntityRepo.save(deviceEntity);
        }
        // 如果设备显示离线状态，只要收到消息了，把设备修改为上线状态
 /*        if(!deviceEntity.getOnline()){
            log.error("{}设备显示离线，但设备仍在接收消息，更新设备状态为上线",deviceEntity.getImei());
            deviceEntityRepo.save(deviceEntity);
        }*/
        // 对应设备属性3个状态位，分别为工作，未启动,故障位
        byte[] flag = new byte[3];
        for (int i = 1; i < allProperties.size(); i++) {
            // PumpConstant.PUMP_STATUS + i + 1 对应的是几号泵的状态
            String pumpStatusName = PumpConstant.PUMP_STATUS + i;
            int status = allProperties.get(pumpStatusName) == null ? 0 : Integer.parseInt(allProperties.get(pumpStatusName));
            log.info("加液泵状态名称{}对应状态{}",pumpStatusName,status);
            // 3个泵中只要有一个处于工作状态中
            if(PumpWorkStatus.RUNNING.getStatus() == status){
                flag[0] = 1;
                continue;
            }
            // 泵处于未启动状态中
            if(PumpWorkStatus.NOT_RUNNING.getStatus() == status){
                flag[1] += 1;
                continue;
            }
            if(PumpWorkStatus.ABNORMAL.getStatus() == status){
                flag[2] += 1;
                continue;
            }
        }
        log.info("当前设备的状态为{}",deviceEntity.getStatus());
        if(flag[0] == 1){
            // 设备启动
            this.onStarted(deviceEntity);
            return;
        }
        // 分为单泵和双泵
        if((flag[2] >= 1 && DeviceType.PUMP_LA_1.getName().equals(deviceEntity.getDeviceType()))
                || (flag[2] >= 2 && DeviceType.PUMP_LA_2.getName().equals(deviceEntity.getDeviceType()))){
            this.onPaused(deviceEntity);
            return;
        }
        // 未启动 + 故障状态合计3台的话
        if(flag[1] + flag[2] == 3){
            // 设备停止
            this.onStopped(deviceEntity);
        }
    }

    private DeviceEntity updateProperties(DeviceInfo deviceInfo){
        DeviceEntity deviceEntity = deviceEntityRepo.findByImei(deviceInfo.getImei());
        if (Objects.isNull(deviceEntity)) {
            return null;
        }
        DevicePropertyEntity timestampEntity = devicePropertyRepo.findByDeviceIdAndPropertyName(deviceEntity.getId(), "timestamp");
        if (null != timestampEntity) {
            String lastUpdateTime = timestampEntity.getPropertyValue();
            if (Long.parseLong(deviceInfo.getTimestamp()) < Long.parseLong(lastUpdateTime)) {
                log.error("设备：{}的属性变更请求时间戳：{}小于属性最近更新时间戳：{}，不进行更新", deviceEntity.getId(), deviceInfo.getTimestamp(), lastUpdateTime);
                return null;
            }
        }
        this.setProperty(deviceEntity.getId(), "timestamp", deviceInfo.getTimestamp());

        for (Map.Entry<String, String> entry : deviceInfo.getAttrs().entrySet()) {
            String propName = entry.getKey();
            if (StringUtils.isNotBlank(propName)) {
                this.setProperty(deviceEntity.getId(), propName, entry.getValue());
            }
        }
        return deviceEntity;
    }

    /**
     * 设备故障
     * @param deviceEntity
     */
    private void onAbnormal(DeviceEntity deviceEntity) {
        if (!DeviceStatus.ABNORMAL.equals(deviceEntity.getStatus())) {
            // 更新运行状态
            deviceEntity.setStatus(DeviceStatus.ABNORMAL);
            deviceEntityRepo.saveAndFlush(deviceEntity);
        }
    }

}
